﻿using PhraseCorrector.Common;
using PhraseCorrector.DirectTanslate;
using PhraseCorrector.SimplePinyin;
using PhraseCorrector.SpellCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading.Tasks;

namespace PhraseCorrector.SpellCorrect
{

    /**
     * 中/西文/拼音对照纠错
     */
    public class ChnEnGPyMache
    {

        #region 变量

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 源语言识别结果，用于存储原始的识别数据
        /// </summary>
        private PhraseResult SourceResult { set; get; } = new PhraseResult();

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 中文识别结果，专门用于存储和处理中文的识别数据
        /// </summary>
        private PhraseResult ChineseResult { set; get; } = new PhraseResult();

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 英文识别结果，专门用于存储和处理英文的识别数据
        /// </summary>
        private PhraseResult EnglishResult { set; get; } = new PhraseResult();

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 拼音识别结果，用于存储拼音的识别数据，可能用于中文相关的识别处理
        /// </summary>
        private PhraseResult PinyinResult { set; get; } = new PhraseResult();

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 综合识别结果，用于存储最终的、综合各种识别处理的结果
        /// </summary>
        public PhraseResult SuggestResult { set; get; } = new PhraseResult();

        #endregion

        #region 初始化并生成识别结果

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 通过提供的中文或英文关键字进行中英文匹配。
        /// </summary>
        /// <param name="source">包含中文和英文关键字的源对象。</param>
        /// <returns>返回一个新的ECResult对象，包含匹配结果。</returns>
        public ChnEnGPyMache(string chinese, string letters)
        {
            SetSource(chinese, letters);
            GetResult(SourceResult);
            GetMaxCoreResult();
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 设置源文本，包括中文和字母文本。
        /// </summary>
        /// <param name="chinese">中文文本</param>
        /// <param name="letters">字母文本</param>
        public void SetSource(string chinese, string letters)
        {
            SourceResult = new PhraseResult()
            {
                Chinese = chinese,
                Words = letters
            };
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取各种语言结果。
        /// </summary>
        /// <param name="source">包含源中文和字母文本的结果对象。</param>
        private void GetResult(PhraseResult source)
        {
            GetChineseResult(source);
            GetPinyinResult(source);
            GetEnglishResult(source);
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取中文拼写检查结果。
        /// </summary>
        /// <param name="source">包含源中文文本的结果对象。</param>
        private void GetChineseResult(PhraseResult source)
        {
            ChineseResult = string.IsNullOrEmpty(source.Chinese)
            ? new PhraseResult()
            : ChineseTraslator.SpellPhraseCorrect(source.Chinese);
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取字母拼写检查结果。
        /// </summary>
        /// <param name="source">包含源字母文本的结果对象。</param>
        private void GetEnglishResult(PhraseResult source)
        {
            EnglishResult = string.IsNullOrEmpty(source.Words)
            ? new PhraseResult()
            : EnglishTraslator.SpellPhraseCorrect(source.Words);
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取拼音拼写检查结果。
        /// </summary>
        /// <param name="source">包含源中文文本和字母文本的结果对象。</param>
        private void GetPinyinResult(PhraseResult source)
        {
            PinyinResult = string.IsNullOrEmpty(source.Words)
                ? new PhraseResult()
                : PinyinTranslator.SpellPhraseCorrect(source.Words);
        }

        #endregion

        #region 核心算法：获取相似度

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取最高相似度的结果。
        /// </summary>
        private void GetMaxCoreResult()
        {
            SuggestResult = GetMaxCoreResult_Result(GetMaxCoreResult_similary(), GetPinyinResult_similary()).result;
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 获取最高相似度的结果。
        /// </summary>
        /// <param name="chn">中文、英文、拼音三种汉字纠错结果与源汉字短语的相似度</param>
        /// <param name="word">中文、英文、拼音三种字母类纠错结果与源字母短语的相似度</param>
        /// <returns>返回最大相似度及对应的词组结果</returns>
        private (double similary, PhraseResult result) GetMaxCoreResult_Result(
            (double chn, double eng, double py) chn,
            (double chn, double eng, double py) word)
        {

            // 计算两个词组在中文、英文和拼音环境下的相似度总和
            var ret = (chn.chn + word.chn, chn.eng + word.eng, chn.py + word.py);

            // 获取每个环境下相似度总和的最大值
            var chnSimilarity = GetMaxCoreResult_Array(ret);

            // 根据中文环境的相似度总和是否最大来决定返回的最大相似度值
            return (ret.Item1 > ret.Item2 && ret.Item1 > ret.Item3)
                ? chnSimilarity.Max()
                : chnSimilarity[..3].Max();
        }

        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 根据给定的语言特征值，获取最大匹配结果的数组。
        /// </summary>
        /// <param name="ret">包含中文、英文和拼音相似度的元组。</param>
        /// <returns>返回一个元组数组，每个元组包含相似度和对应的短语结果。</returns>
        private (double similary, PhraseResult result)[] GetMaxCoreResult_Array((double chn, double eng, double py) ret)
        {
            // 创建并返回一个包含多个语言匹配结果的数组
            // 包含的元素按顺序分别是：初始结果、英文匹配结果、拼音匹配结果和中文匹配结果
            return new (double similary, PhraseResult result)[] {
                (0, SourceResult), // 初始结果，相似度设为0
                (ret.eng, EnglishResult), // 英文匹配结果，使用给定的英文相似度
                (ret.py, PinyinResult), // 拼音匹配结果，使用给定的拼音相似度
                (ret.chn, ChineseResult) // 中文匹配结果，使用给定的中文相似度
            };
        }
        ////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 计算各语言与源结果的相似度
        /// </summary>
        /// <returns>返回一个元组，包含中、英、拼音与源结果的相似度</returns>
        private (double chn, double eng, double py) GetMaxCoreResult_similary()
        {
            // 使用SpellCoefficient类的Similarity方法计算相似度并返回元组
            return (
                SpellCoefficient.Similarity(ChineseResult.Chinese, SourceResult.Chinese),
                SpellCoefficient.Similarity(EnglishResult.Chinese, SourceResult.Chinese),
                SpellCoefficient.Similarity(PinyinResult.Chinese, SourceResult.Chinese)
            );
        }

        /// <summary>
        /// 计算各语言字母类与源words词汇之间的相似度
        /// </summary>
        /// <remarks>
        /// 计算拼音、英文、汉字与源数据的相似度
        /// 1、汉字： 使用结果汉字与源汉字进行相似度计算，
        /// 2、英文：如果英文的相似度结果中汉字部分为空，则结果无效，强制相似度为零；反之对源数据英文部分和结果计算两者间的相似度。 
        /// 3、拼音：如果结果相似度中汉字部分为空，则结果无效，强制相似度为零；反之对源数据拼音部分和结果拼音计算两者间的相似度。 
        /// </remarks>
        /// <returns>返回一个元组，包含中、英、拼音中字母词汇与源结果的相似度 </returns>
        private (double chn, double eng, double py) GetPinyinResult_similary()
        {
            var ch = ChineseResult.Words.Split('|');
            // 使用SpellCoefficient类的Similarity方法计算相似度并返回元组
            return (
                 Math.Max(SpellCoefficient.Similarity(ch[0], SourceResult.Words), SpellCoefficient.Similarity(ch[ch.Length - 1], SourceResult.Words)),
                 EnglishResult.Chinese.Length > 0 ? SpellCoefficient.Similarity(EnglishResult.Words, SourceResult.Words) : 0,
                PinyinResult.Chinese.Length > 0 ? SpellCoefficient.Similarity(PinyinResult.Words, SourceResult.Words) : 0
            );
        }

        #endregion
    }
}
